﻿using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using MaxStoreErp.Core.Annotations;
using MaxStoreErp.Core.Exceptions;
using MaxStoreErp.Core.Interfaces;
using MaxStoreShop.Core.Contracts;

namespace MaxStoreShop.Core.Services
{
    public class UserXmlSettings : INotifyPropertyChanged, ISettings
    {
        [Microsoft.Practices.Unity.Dependency]
        public ILogger Logger { get; set; }

        const string FileName = "Settings.xml";
        readonly string _settingPath;
        string _workFolder;
        string _organizationName;
        string _debtorsFotoFolder;
        string _tempFolder;
        string _productsFotoFolder;
        string _connectionString;
        string _updateFolder;

        public UserXmlSettings()
        {
            _settingPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "MaxStoreShopData");
        }

        public string WorkFolder
        {
            get { return _workFolder; }
            set
            {
                _workFolder = value;
                OnPropertyChanged();
            }
        }

        public string OrganizationName
        {
            get { return _organizationName; }
            set
            {
                _organizationName = value;
                OnPropertyChanged();
            }
        }

        public string DebtorsFotoFolder
        {
            get { return _debtorsFotoFolder; }
            private set
            {
                _debtorsFotoFolder = value;
                OnPropertyChanged();
            }
        }

        public string TempFolder
        {
            get { return _tempFolder; }
            private set
            {
                _tempFolder = value;
                OnPropertyChanged();
            }
        }

        public string ProductsFotoFolder
        {
            get { return _productsFotoFolder; }
            private set
            {
                _productsFotoFolder = value;
                OnPropertyChanged();
            }
        }

        public string ConnectionString
        {
            get { return _connectionString; }
            set
            {
                _connectionString = value;
                OnPropertyChanged();
            }
        }

        public string UpdateFolder
        {
            get { return _updateFolder; }
            set
            {
                _updateFolder = value;
                OnPropertyChanged();
            }
        }

        public void LoadSettings()
        {
            var document = PrepareFile();
            GetWorkFolder(document.Root);
            GetOrganizationData(document.Root);
            GetConnectionData(document.Root);
            GetUpdateData(document.Root);
            GetDebtorsFotoFolder();
            GetProductsFotoFolder();
            GetTempFolder();
        }

        XDocument PrepareFile()
        {
            try
            {
                if (!Directory.Exists(_settingPath))
                    Directory.CreateDirectory(_settingPath);

                if (!File.Exists(Path.Combine(_settingPath, FileName)))
                    CreateDefaultSettingsFile();

                return XDocument.Load(Path.Combine(_settingPath, FileName));

            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка загрузки файла конфигурации. {0}", exception.Message), exception);
            }
        }

        void CreateDefaultSettingsFile()
        {
            WorkFolder = @"C:\";
            OrganizationName = "Рога и копыта Инт.";
            ConnectionString = @"Data Source=WB-996\SQLEXPRESS;Initial Catalog=Shop;Integrated Security=True;MultipleActiveResultSets=True";
            Save();
        }

        void GetWorkFolder(XContainer documentRoot)
        {
            try
            {
                var workFolderNode = documentRoot.Element("WorkFolder");
                if (workFolderNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутствует элемент WorkFolder!");

                var xElement = workFolderNode.Element("value");
                if (xElement == null)
                    throw new ErpRuntimeException("В файле настроек WorkFolder отсутсвует элемент value!");

                WorkFolder = xElement.Value;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(
                    string.Format("Ошибка чтения конфигурации рабочей директории. {0}", exception.Message), exception);
            }
        }

        void GetOrganizationData(XContainer documentRoot)
        {
            try
            {
                var organizationNode = documentRoot.Element("Organization");
                if (organizationNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутствует элемент Organization!");

                var organizationNameNode = organizationNode.Element("Name");
                if (organizationNameNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутствует элемент Name в разделе Organization!");

                OrganizationName = organizationNameNode.Value;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(
                    string.Format("Ошибка чтения конфигурации рабочей директории. {0}", exception.Message), exception);
            }
        }

        void GetDebtorsFotoFolder()
        {
            try
            {
                var path = Path.Combine(WorkFolder, WorkFolders.DebtorsFotoFolder);
                if (!Directory.Exists(path))
                {
                    Logger.LogInfo("Создание директории фотографий должников...");
                    Directory.CreateDirectory(path);
                }

                DebtorsFotoFolder = path;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка получения пути к каталогу фотографий должников. {0}", exception.Message), exception);
            }
        }

        void GetProductsFotoFolder()
        {
            try
            {
                var path = Path.Combine(WorkFolder, WorkFolders.ProductsFotoFolder);
                if (!Directory.Exists(path))
                {
                    Logger.LogInfo("Создание директории фотографий продуктов...");
                    Directory.CreateDirectory(path);
                }
                ProductsFotoFolder = path;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка получения пути к каталогу фотографий продуктов. {0}", exception.Message), exception);
            }
        }

        void GetTempFolder()
        {
            try
            {
                var path = Path.Combine(_settingPath, WorkFolders.TempFolder);
                if (!Directory.Exists(path))
                {
                    Logger.LogInfo("Создание директории временных файлов...");
                    Directory.CreateDirectory(path);
                }
                TempFolder = path;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка получения пути к каталогу временных файлов. {0}", exception.Message), exception);
            }
        }

        void GetConnectionData(XContainer documentRoot)
        {
            try
            {
                var connectionNode = documentRoot.Element("Connection");
                if (connectionNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутствует элемент Connection!");

                var connectionStringNode = connectionNode.Element("string");
                if (connectionStringNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутсвует элемент string в разделе Connection!");

                ConnectionString = connectionStringNode.Value;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка получения данных подключения. {0}", exception.Message), exception);
            }
        }

        void GetUpdateData(XContainer documentRoot)
        {
            try
            {
                var connectionNode = documentRoot.Element("Update");
                if (connectionNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутствует элемент Update!");

                var connectionStringNode = connectionNode.Element("FolderPath");
                if (connectionStringNode == null)
                    throw new ErpRuntimeException("В файле настроек отсутсвует элемент FolderPath в разделе Update!");

                UpdateFolder = connectionStringNode.Value;
            }
            catch (Exception exception)
            {
                throw new ErpRuntimeException(string.Format("Ошибка получения данных обновления. {0}", exception.Message), exception);
            }
        }

        public void Save()
        {
            var document = new XDocument(
                new XElement("StoreErpSettings",
                    new XElement("WorkFolder",
                        new XElement("value", WorkFolder)),
                    new XElement("Organization",
                        new XElement("Name", OrganizationName)),
                    new XElement("Connection",
                        new XElement("string", ConnectionString)),
                    new XElement("Update",
                        new XElement("FolderPath", UpdateFolder))));

            document.Save(Path.Combine(_settingPath, FileName));
        }

        #region INotifyPropertyChanged

        #endregion

        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
